package Server;

import communication.GameMessage;
import communication.GameRequest;
import logic.Board;

public class Game extends Thread{
	
	@SuppressWarnings("unused")
	private Server server;
	private ServerData sdata;
	
	public static int STATE_INITIAL = 301;
	public static int STATE_RUNNING = 302;
	public static int STATE_FINISHED = 303;

	private Player player1;
	private Player player2;
	
	private Player currentPlayer;
	
	private Board board1 = null;
	private Board board2 = null;
	
	private int gameState;
	
	
	/*-----------------------------------*/
	
	public Game(Player p1, Player p2, Server server) {
		
		this.server = server;
		this.sdata = server.getData();
		
		this.player1 = p1;
		this.player2 = p2;
		
		this.currentPlayer = p1;
		this.gameState = STATE_INITIAL;
		
		board1 = Board.getDefaultBoard();
		board2 = Board.getDefaultBoard();

		System.out.println("Starting game between " + player1.getUser().getUserName() + " and " 
				+ player2.getUser().getUserName() + "...");
		
	}
	
	public int getGameState() {
		return gameState;
	}

	public void setGameState(int gameState) {
		this.gameState = gameState;
	}

	public Player getPlayer1() {
		return player1;
	}

	public Player getPlayer2() {
		return player2;
	}
	
	public void switchPlayer(){
		
		if (currentPlayer==player1)
			currentPlayer = player2;
		else
			currentPlayer = player1;
	}

	public Player getCurrentPlayer(){
		return currentPlayer;
	}
	
	
	/**
	 * Handles any request sent during a game by the client.
	 * 
	 * 
	 */
	public void handleGameRequest(GameRequest request, Player p){
		
		if (request!=null)
			switch(request.getType()){
			
			case GameRequest.REQ_CONFIG:

				if (gameState==STATE_INITIAL)
					if (request.getBoard()!=null && request.getBoard().isReadyToStart()){

						if (p == player1)
							board1 = request.getBoard();
						else
							board2 = request.getBoard();


						p.sendGameMessage(new GameMessage(GameMessage.GAME_CONFIG_OK));
						getEnemyOf(p).sendGameMessage(new GameMessage(GameMessage.GAME_ENEMY_CONFIGURED));

						
						if (board1.isReadyToStart() && board2.isReadyToStart()){
							this.gameState = STATE_RUNNING;
							
							GameMessage msg = new GameMessage(GameMessage.GAME_START);
							msg.setFirstToPlay(false);
							p.sendGameMessage(msg);
							
							msg.setFirstToPlay(true);
							currentPlayer = getEnemyOf(p);
							getEnemyOf(p).sendGameMessage(msg);		
							
							server.getRmiNavalBattle().updateGames(server);
							
						}

					}
				
				
				break;
				
			case GameRequest.REQ_MSG:
				//Not to be implemented	
				break;
							
			case GameRequest.REQ_PLAY:
				
				GameMessage msg;
				
				if (gameState==STATE_RUNNING)
					if (currentPlayer==p){
						
						int res = getBoardOf(getEnemyOf(p)).shotAt(request.getLine(), request.getColumn());
						
						
						switch (res){
						
						case Board.SHIP_HIT:
							
							msg = new GameMessage(GameMessage.GAME_MY_MOVE_RES);
							msg.setLine(request.getLine());
							msg.setColumn(request.getColumn());
							msg.setOnShip(true);
							p.sendGameMessage(msg);
							
							msg = new GameMessage(GameMessage.GAME_ENEMY_MOVE);
							msg.setLine(request.getLine());
							msg.setColumn(request.getColumn());
							msg.setOnShip(true);
							getEnemyOf(p).sendGameMessage(msg);
							
							
							switchPlayer();
							
							break;
							
						case Board.SHIP_HIT_WRECKED:
						
							msg = new GameMessage(GameMessage.GAME_MY_MOVE_RES);
							msg.setLine(request.getLine());
							msg.setColumn(request.getColumn());
							msg.setOnShip(true);
							msg.setShipDestroyed(true);
							msg.setShip(getBoardOf(getEnemyOf(p)).getShipAt(request.getLine(), request.getColumn()));
							
							p.sendGameMessage(msg);
							

							msg = new GameMessage(GameMessage.GAME_ENEMY_MOVE);
							msg.setLine(request.getLine());
							msg.setColumn(request.getColumn());
							msg.setOnShip(true);
							msg.setShipDestroyed(true);
							msg.setShip(getBoardOf(getEnemyOf(p)).getShipAt(request.getLine(), request.getColumn()));
							
							getEnemyOf(p).sendGameMessage(msg);
							

							if (getBoardOf(getEnemyOf(p)).isAllShipsWrecked()){
								gameState = STATE_FINISHED;
								
								p.sendGameMessage(new GameMessage(GameMessage.GAME_WIN));
								getEnemyOf(p).sendGameMessage(new GameMessage(GameMessage.GAME_OVER));
								
								ended();
								
							}
							else
								switchPlayer();

							break;
							
						case Board.SHIP_MISSED:
						
							msg = new GameMessage(GameMessage.GAME_MY_MOVE_RES);
							msg.setLine(request.getLine());
							msg.setColumn(request.getColumn());
							msg.setOnShip(false);
							msg.setShipDestroyed(false);
							
							p.sendGameMessage(msg);
							
							msg = new GameMessage(GameMessage.GAME_ENEMY_MOVE);
							msg.setLine(request.getLine());
							msg.setColumn(request.getColumn());
							msg.setOnShip(false);
							msg.setShipDestroyed(false);
							
							getEnemyOf(p).sendGameMessage(msg);
							
							
							switchPlayer();
							
						}


					}

				break;
				
			case GameRequest.REQ_QUIT:
				
				quit(p);
				
				break;
			
			default:
				System.err.println("Invalid Game Request Received! - type: " + request.getType());
			
		}
	}
	
	
	private void ended(){
		
		this.gameState = Game.STATE_FINISHED;
		
		System.out.println("Game between "+ player1.getUser().getUserName() +" and "+player2.getUser().getUserName()  +" Ended");
		player1.setPlayerState(Player.STATE_CONNECTED);
		player2.setPlayerState(Player.STATE_CONNECTED);		
		player1.setGame(null);
		player2.setGame(null);
		sdata.getGames().remove(this);
		
		server.getRmiNavalBattle().updateGames(server);
		
	}


	public Player getEnemyOf(Player p) {
				
		if (p==player1)
			return player2;
		else
			if (p==player2)
				return player1;
			else
				return null;
		
	}
	
	public static Board getDefaultBoard(){
		
		Board b = new Board(9, 9);
		
		return b;
		
	}
	
	public Board getBoardOf(Player p){
		if (p == player1)
			return board1;
		else
			if (p == player2)
				return board2;
			else
				return null;
	}
	
	public void quit(Player p){
		
		getEnemyOf(p).sendGameMessage(new GameMessage(GameMessage.GAME_QUIT));
		ended();
		
		
	}
	
}
